// @Author yy 2024/8/20
package conference_handler

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"peilian-api/app/global/bind"
	"peilian-api/app/global/errors"
	"peilian-api/app/global/variable"
	"peilian-api/utils/format"
	"peilian-api/utils/httpClientUtil"
	"peilian-api/utils/shengWangUtil"
	"strconv"
	"time"
)

type SwTokenDTO struct {
	ChannelName string `json:"channelName"`
	Uid         string `json:"uid"`
	UserToken   string `json:"userToken"`
	Resourceid  string `json:"resourceid"`
	Sid         string `json:"sid"`
}

/**
*@author: yy
*@description: 前端进入频道，需要后端生成token
*@date :2024/8/20 上午9:16
**/
func GetToken(ctx *gin.Context) {
	var tokenDTO SwTokenDTO
	if err := bind.ShouldBinding(ctx, &tokenDTO); err != nil {
		format.NewResponseJson(ctx).Err(errors.PublicErrorCode, errors.ParamBindError)
		return
	}
	log.Printf("获取到参数 == channelName: %s, uid: %s", tokenDTO.ChannelName, tokenDTO.Uid)
	if len(tokenDTO.ChannelName) == 0 || len(tokenDTO.Uid) == 0 {
		format.NewResponseJson(ctx).Err(errors.RequestParamsEmptyCode, "请求参数不能为空")
	}
	token, err := shengWangUtil.GetShenWangToken(tokenDTO.ChannelName, tokenDTO.Uid)
	if err != nil {
		format.NewResponseJson(ctx).Err(errors.PublicErrorCode, "生成token失败")
	}
	log.Printf("生成的token: %s", token)
	m := map[string]string{
		"token": token}
	format.NewResponseJson(ctx).SuccessObj(m)
}

func GetAcquire(channelName, uid string) (token string) {
	customerToken := shengWangUtil.GetCustomerToken(variable.Config.ShengWang.CustomerKey, variable.Config.ShengWang.CustomerSecret)
	url := variable.Config.ShengWang.CommonUrl + variable.Config.ShengWang.Appid + "/cloud_recording/acquire"
	clientRequestMap := map[string]int{
		"scene":               0,
		"resourceExpiredHour": 24,
	}
	paramMap := map[string]interface{}{
		"cname":         channelName,
		"uid":           uid,
		"clientRequest": clientRequestMap}
	marshal, err := json.Marshal(paramMap)
	if err != nil {
		fmt.Println("转换json 失败")
	}
	log.Printf("获取到的url = %s,请求参数 = %s", url)
	resultMap := httpClientUtil.DoPostTakeToken(url, string(marshal), customerToken)
	resourceId := resultMap["resourceId"]
	fmt.Println("获取云端录制资格resourceId =  %s", resourceId)
	return resourceId.(string)
}

/**
*@author: yy
*@description: 声网开始录制功能，
 开始云端录制功能，其实就是往频道中插入一个机器人专门去录制，需要保证频道的所有人的uid必须是唯一的。
*@date :2024/8/20 上午9:16
**/
func StartRecordConference(ctx *gin.Context) {
	var tokenDTO SwTokenDTO
	if err := bind.ShouldBinding(ctx, &tokenDTO); err != nil {
		format.NewResponseJson(ctx).Err(errors.PublicErrorCode, errors.ParamBindError)
		return
	}
	headerToken := shengWangUtil.GetCustomerToken(variable.Config.ShengWang.CustomerKey, variable.Config.ShengWang.CustomerSecret)
	timestamp := time.Now().Unix()
	tokenDTO.Uid = strconv.FormatInt(timestamp, 10)
	// userTOken
	wangToken, err2 := shengWangUtil.GetShenWangToken(tokenDTO.ChannelName, tokenDTO.Uid)
	if err2 != nil {
		format.NewResponseJson(ctx).Err(500, "token生成失败")
		return
	}
	// 获取云端录制资格 resourceId
	resourceId := GetAcquire(tokenDTO.ChannelName, tokenDTO.Uid)
	//本次录制采用 单流录制模式
	recordUrl := variable.Config.ShengWang.CommonUrl + variable.Config.ShengWang.Appid + "/cloud_recording/resourceid/" + resourceId + "/mode/individual/start"
	// 录制文件存放第三方平台配置信息
	storageConfigMap := map[string]interface{}{
		"vendor":         2,
		"region":         3,
		"bucket":         variable.Config.AliOss.AliBucket,
		"accessKey":      variable.Config.AliOss.AliAccessKey,
		"secretKey":      variable.Config.AliOss.AliSecretKey,
		"fileNamePrefix": []string{"leaderVideoFile", tokenDTO.ChannelName}}
	// 录音文件配置信息
	recordingConfigMap := map[string]interface{}{
		"maxIdleTime":       240, // 最大设置30天 单位秒  目前设置2小时
		"subscribeUidGroup": 2,
		"streamMode":        "original", // 媒体流的输出模式。详见媒体流输出模式。 原始编码模式。适用于单流音频不转码录制。仅订阅音频时
		"channelType":       1,          // 频道场景。0：通信场景。1：直播场景。
		// 订阅的媒体流类型。0：仅订阅音频。适用于智能语音审核场景。 1：仅订阅视频。2：订阅音频和视频。
		"streamTypes": 0}
	// 拼接请求参数
	clientRequestMap := map[string]interface{}{
		"token":           wangToken,
		"storageConfig":   storageConfigMap,
		"recordingConfig": recordingConfigMap}
	paramMap := map[string]interface{}{
		"cname":         tokenDTO.ChannelName,
		"uid":           tokenDTO.Uid,
		"clientRequest": clientRequestMap}
	marshal, err := json.Marshal(paramMap)
	if err != nil {
		format.NewResponseJson(ctx).Err(500, "参数转换失败")
		return
	}
	log.Printf("开始云端录制[入参] ====url:%s\n,param:%s\n,token :%s\n", recordUrl, marshal, headerToken)
	// 处理完成的数据
	resu := httpClientUtil.DoPostTakeToken(recordUrl, string(marshal), headerToken)
	log.Printf("开始云端录制[返参]  ====result:%s\n", resu)
	format.NewResponseJson(ctx).SuccessObj(resu)
}

// StopRecordConference
/**
*@author: yy
*@description: 停止云端录制 获取文件地址
*@date :2024/8/20 下午5:02
**/
//func StopRecordConference(ctx *gin.Context) {
//	var tokenDTO SwTokenDTO
//	if err := bind.ShouldBinding(ctx, &tokenDTO); err != nil {
//		format.NewResponseJson(ctx).Err(errors.PublicErrorCode, errors.ParamBindError)
//		return
//	}
//	// 这里用时间戳的目的是因为录制是采用机器人形式，但是要保证频道内的uid是唯一的。
//	timestamp := time.Now().Unix()
//	tokenDTO.Uid = strconv.FormatInt(timestamp, 10)
//	// 获取到 channelName  uid ,resourceId,sid
//	stopUrl := variable.Config.ShengWang.CommonUrl + variable.Config.ShengWang.Appid + "/cloud_recording/resourceid/" + tokenDTO.Resourceid + "/sid/" + tokenDTO.Sid + "/mode/individual/stop"
//	// 开始拼接数据
//	clientRequest := map[string]interface{}{
//		"async_stop": true}
//	paramMap := map[string]interface{}{
//		"cname":         tokenDTO.ChannelName,
//		"uid":           tokenDTO.Uid,
//		"clientRequest": clientRequest,
//	}
//	customerToken := shengWangUtil.GetCustomerToken(variable.Config.ShengWang.CustomerKey, variable.Config.ShengWang.CustomerSecret)
//	marshal, err := json.Marshal(paramMap)
//	if err != nil {
//		format.NewResponseJson(ctx).Err(500, "参数解析错误")
//		return
//	}
//	log.Printf("停止云端录制[入参],url :%s\n,param:%s\n,token:%s\n", stopUrl, marshal, customerToken)
//	result := httpClientUtil.DoPostTakeToken(stopUrl, string(marshal), customerToken)
//	bytes, err := json.Marshal(result)
//	if err != nil {
//		format.NewResponseJson(ctx).Err(500, "返回参数格式化失败")
//		return
//	}
//	log.Printf("停止云端录制[返参] =result :%s\n", bytes)
//	value, ok := result["code"]
//	// 录制成功的接口中没有code
//	if !ok {
//		serverResponse, ok := result["serverResponse"].(map[string]interface{})
//		if !ok {
//			format.NewResponseJson(ctx).Err(500, "返回参数获取内容失败")
//			return
//		}
//		filelist := serverResponse["fileList"].([]interface{})
//		if filelist != nil && len(filelist) != 0 {
//			m := filelist[0].(map[string]interface{})
//			m2 := map[string]interface{}{
//				"fileName": m["fileName"]}
//			fmt.Println("返回参数:", m["fileName"])
//			format.NewResponseJson(ctx).SuccessObj(m2)
//			return
//		}
//	} else {
//		log.Printf("停止录制出现问题====uid:%s\n,resourceid:%s\n,sid:%s\n", tokenDTO.Uid, tokenDTO.Resourceid, tokenDTO.Sid)
//		// 出问题的时候了
//		if value == "435" {
//			format.NewResponseJson(ctx).SuccessObj(435, fmt.Errorf("没有录制文件产生。频道内没有用户发流，无录制对象。"))
//			return
//		} else if value == "404" {
//			format.NewResponseJson(ctx).SuccessObj(404, fmt.Errorf("服务器无法根据请求找到资源（网页）"))
//			return
//		} else {
//			format.NewResponseJson(ctx).SuccessObj(500, fmt.Errorf("其他错误，请联系管理员"))
//			return
//		}
//
//	}
//
//}
func StopRecordConference(cname, uid, resourceid, sid string) (fileName string, error *errors.ErrRes) {

	// 获取到 channelName  uid ,resourceId,sid
	stopUrl := variable.Config.ShengWang.CommonUrl + variable.Config.ShengWang.Appid + "/cloud_recording/resourceid/" + resourceid + "/sid/" + sid + "/mode/individual/stop"
	// 开始拼接数据
	clientRequest := map[string]interface{}{
		"async_stop": true}
	paramMap := map[string]interface{}{
		"cname":         cname,
		"uid":           uid,
		"clientRequest": clientRequest,
	}
	customerToken := shengWangUtil.GetCustomerToken(variable.Config.ShengWang.CustomerKey, variable.Config.ShengWang.CustomerSecret)
	marshal, err := json.Marshal(paramMap)
	if err != nil {
		return "", errors.NewErrInfo(500, fmt.Errorf("参数解析错误"))
	}
	log.Printf("停止云端录制[入参],url :%s\n,param:%s\n,token:%s\n", stopUrl, marshal, customerToken)
	result := httpClientUtil.DoPostTakeToken(stopUrl, string(marshal), customerToken)
	bytes, err := json.Marshal(result)
	if err != nil {
		return "", errors.NewErrInfo(500, fmt.Errorf("返回参数格式化失败"))

	}
	log.Printf("停止云端录制[返参] =result :%s\n", bytes)
	value, ok := result["code"]
	// 录制成功的接口中没有code
	if !ok {
		serverResponse, ok := result["serverResponse"].(map[string]interface{})
		if !ok {
			return "", errors.NewErrInfo(500, fmt.Errorf("返回参数获取内容失败"))
		}
		filelist := serverResponse["fileList"].([]interface{})
		if filelist != nil && len(filelist) != 0 {
			m := filelist[0].(map[string]interface{})
			return m["fileName"].(string), nil
		}
		return "", errors.NewErrInfo(500, fmt.Errorf("其他错误，请联系管理员"))
	} else {
		log.Printf("停止录制出现问题====uid:%s\n,resourceid:%s\n,sid:%s\n", uid, resourceid, sid)
		// 出问题的时候了
		if value == "435" {
			return "", errors.NewErrInfo(435, fmt.Errorf("没有录制文件产生。频道内没有用户发流，无录制对象。"))
		} else if value == "404" {
			return "", errors.NewErrInfo(404, fmt.Errorf("服务器无法根据请求找到资源（网页）"))
		}
		return "", errors.NewErrInfo(500, fmt.Errorf("其他错误，请联系管理员"))
	}
}
